﻿/************************************************************************
 * CoreDES - A small and core library for discrete event systems
 * Copyright (C) 2012-2013 Ali Khalili (khalili_DOT_ir_@SIGN_gmail_DOT_com)
 * **********************************************************************
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License (LGPL) published 
 * by the Free Software Foundation; either version 2.1 of the License, or (at your
 * option) any later version. This program is distributed without any
 * warranty. See the GNU Lesser General Public License for more details. 
 * ***********************************************************************
 * File         :     CoreDES\Execution\Function.cs
 * Description  :     The container of a function
 * Change log   :     -oct 2013: initial version 
 * To Do        :
 ************************************************************************/
using System;
using System.Reflection;

namespace CoreDES.Execution
{

    /// <summary>
    /// The container of a function (signiture of the function and possible its handler) with unknown type and unknown number
    /// of parameters
    /// </summary>
    public class Function : ExecutableMethod
    {
        /// <summary>
        /// It is not allowed!
        /// </summary>
        private Function()
        {
            //* nothing
        }

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="handler">the handler</param>
        /// <param name="target">the target object</param>
        public Function(MethodInfo handler, object target = null)
            : base(handler, target)
        {
            if (handler.ReturnType == typeof(void))
                throw new Exception("The signiture is related to procedure not a function");
        }
    }

    //**********************************************************************************************************

    /// <summary>
    /// A function (with one return value) without any parameter. 
    /// <remarks>
    /// The execution is provided by delegate (which is faster than reflection)
    /// </remarks>
    /// </summary>
    /// <typeparam name="RetType">type of return value</typeparam>
    public class Function<RetType> : Function
    {
        delegate RetType myDeligate();

        myDeligate funcHandle;

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="m">the method info</param>
        /// <param name="target">the target object</param>
        public Function(MethodInfo m, object target)
            : base(m)
        {
            SetHandler(m, target);
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="method"></param>
        /// <param name="target"></param>
        void SetHandler(MethodInfo method, object target)
        {
            funcHandle = (myDeligate)Delegate.CreateDelegate(typeof(myDeligate), target, method, false);
            if (funcHandle == null)
                throw new Exception("Error: Function not resolved!");
        }

        /// <summary>
        /// Execute by handler
        /// </summary>
        /// <returns>the return value</returns>
        public RetType ExecuteByHandle()
        {
            return funcHandle();
        }
    }

    //**********************************************************************************************************

    /// <summary>
    /// A function with one parameter
    /// </summary>
    /// <typeparam name="RetType">type of return value</typeparam>
    /// <typeparam name="P1Type">type of the -only- parameter</typeparam>
    public class Function<RetType, P1Type> : Function
    {
        delegate RetType myDeligate(P1Type myParam1);

        myDeligate funcHandle;

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="m">the methodinfo</param>
        /// <param name="target">target object</param>
        public Function(MethodInfo m, object target)
            : base(m)
        {
            SetHandler(m, target);
        }

        private void SetHandler(MethodInfo method, object target)
        {
            funcHandle = (myDeligate)Delegate.CreateDelegate(typeof(myDeligate), target, method, false);
            if (funcHandle == null)
                throw new Exception("Error: Function not resolved!");
        }

        /// <summary>
        /// Execute it by delegate
        /// </summary>
        /// <param name="p1">the parameter</param>
        /// <returns>return value</returns>
        public RetType ExecuteByHandle(P1Type p1)
        {
            return funcHandle(p1);
        }
    }


    //**********************************************************************************************************

    /// <summary>
    /// A function with two parameters
    /// </summary>
    /// <typeparam name="RetType">type of return value</typeparam>
    /// <typeparam name="P1Type">type of first parameters</typeparam>
    /// <typeparam name="P2Type">type of second parameters</typeparam>
    public class Function<RetType, P1Type, P2Type> : Function
    {
        delegate RetType myDeligate(P1Type myParam1, P2Type myParam2);
        myDeligate funcHandle;

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="m">the method info</param>
        /// <param name="target">the target object</param>
        public Function(MethodInfo m, object target)
            : base(m, target)
        {
            SetHandler(m, target);
        }

        /// <summary>
        /// Set delegate
        /// </summary>
        /// <param name="method"></param>
        /// <param name="target"></param>
        void SetHandler(MethodInfo method, object target)
        {
            funcHandle = (myDeligate)Delegate.CreateDelegate(typeof(myDeligate), target, method, false);
            if (funcHandle == null)
                throw new Exception("Error: Function not resolved!");
        }

        /// <summary>
        /// Execute function by delegate
        /// </summary>
        /// <param name="p1">first parameter</param>
        /// <param name="p2">second parameter</param>
        /// <returns>return value of function</returns>
        public RetType ExecuteByHandle(P1Type p1, P2Type p2)
        {
            return funcHandle(p1, p2);
        }
    }
}
